﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Data
{
    public interface IEntity
    {
        Int64 Id { get; set; }
    }
    public class DataContext : DbContext
    {
        public DataContext(string connectionString)
            : base(connectionString)
        {

        }

        public DbSet<UserProfile> UserProfiles { get; set; }
        public DbSet<UserReport> UserReports { get; set; }
        public DbSet<UserBookmark> UserBookmarks { get; set; }
        public DbSet<Url> Url { get; set; }
        public DbSet<Tag> Tag { get; set; }
        public DbSet<Bookmark> Bookmarks { get; set; }
        public DbSet<UserUrlSettings> UserUrlSettings { get; set; }

        protected override void OnModelCreating(DbModelBuilder mb)
        {
            base.OnModelCreating(mb);
            //здесь будем вызывать FluentApi

            mb.Entity<UserReport>().HasKey(r => r.Id).Property(r => r.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            mb.Entity<UserReport>().Property(ur => ur.Message).IsRequired().IsUnicode();
            mb.Entity<UserReport>().Property(ur => ur.Title).IsOptional().IsUnicode();
            mb.Entity<UserReport>().Property(ur => ur.Contacts).IsOptional().IsUnicode();
            mb.Entity<UserReport>().Property(ur => ur.UserId).IsRequired();

            mb.Entity<UserBookmark>().HasKey(ub => ub.Id).Property(ub => ub.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            mb.Entity<UserBookmark>().Property(ub => ub.UserId).IsRequired();
            mb.Entity<UserBookmark>().Property(ub => ub.BookmarkId).IsRequired();

            //mb.Entity<Bookmark>().HasKey(b => b.Id)
            ///Посмотреть варианты с таким ключом. Уточнить как можно избавиться от поиска уже существующих записей.
            mb.Entity<Bookmark>().HasKey(b => b.Id).Property(b => b.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            mb.Entity<Bookmark>().Property(b => b.TagId).IsRequired();
            mb.Entity<Bookmark>().Property(b => b.UrlId).IsRequired();

            mb.Entity<Tag>().HasKey(t => t.Id).Property(t => t.Id).IsRequired();
            mb.Entity<Tag>().Property(t => t.TAG).IsRequired();

            mb.Entity<Url>().HasKey(u => u.Id).Property(u => u.Id).IsRequired();//.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            mb.Entity<Url>().Property(u => u.URI).IsRequired().IsUnicode();
            mb.Entity<Url>().Property(u => u.Title).IsOptional();

            mb.Entity<UserUrlSettings>().HasKey(uus => uus.Id).Property(uus => uus.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            mb.Entity<UserUrlSettings>().Property(uus => uus.Title).IsRequired();
            mb.Entity<UserUrlSettings>().Property(uus => uus.UserId).IsRequired();
            mb.Entity<UserUrlSettings>().Property(uus => uus.UrlId).IsRequired();

            mb.Entity<UserProfile>().ToTable("UserProfile");
            mb.Entity<UserProfile>().HasKey(u => u.Id).Property(u => u.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            mb.Entity<UserProfile>().Property(u => u.UserName).IsRequired();

            //One or more validation errors were detected during model generation:

//\tSystem.Data.Entity.Edm.EdmAssociationType: : Multiplicity conflicts with the referential constraint in Role 'Tag_Bookmarks_Source' in relationship 'Tag_Bookmarks'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'.
//\tSystem.Data.Entity.Edm.EdmAssociationConstraint: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'UrlId' on entity 'UserUrlSettings' does not match the type of property 'Id' on entity 'Url' in the referential constraint 'Url_UserUrlSettings'.
//\tSystem.Data.Entity.Edm.EdmAssociationType: : Multiplicity conflicts with the referential constraint in Role 'Url_Bookmarks_Source' in relationship 'Url_Bookmarks'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'.
//\tSystem.Data.Entity.Edm.EdmAssociationConstraint: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'UserId' on entity 'UserBookmark' does not match the type of property 'Id' on entity 'UserProfile' in the referential constraint 'UserProfile_UserBookmarks'.
//\tSystem.Data.Entity.Edm.EdmAssociationConstraint: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'UserId' on entity 'UserReport' does not match the type of property 'Id' on entity 'UserProfile' in the referential constraint 'UserProfile_Reports'.

            mb.Entity<UserProfile>()
                .HasMany(r => r.Reports)
                .WithRequired(r => r.User)
                .HasForeignKey(r => r.UserId)
                .WillCascadeOnDelete(false);

            //Tag - * Bookmark
            mb.Entity<Tag>()
                .HasMany(t => t.Bookmarks)
                .WithRequired(b => b.Tag)
                .HasForeignKey(b => b.TagId)
                .WillCascadeOnDelete(false);

            ////Url 1 - * Bookmark
            mb.Entity<Url>()
                .HasMany(u => u.Bookmarks)
                .WithRequired(b => b.Url)
                .HasForeignKey(b => b.UrlId)
                .WillCascadeOnDelete(false);

            //Bookmark 1 - * UserBookmarks
            mb.Entity<Bookmark>()
                //.HasKey(b => new { b.TagId, b.UrlId })
                .HasMany(b => b.UserBookmarks)
                .WithRequired(ub => ub.Bookmark)
                .HasForeignKey(b => b.BookmarkId)
                .WillCascadeOnDelete(false);
            //mb.Entity<UserBookmark>()
            //    .HasRequired(ub => ub.Bookmark)
            //    .WithMany(b=> b.UserBookmarks)
            //    .HasForeignKey(b=> b.
            //UserProfile 1 - * UserBookmarks
            mb.Entity<UserProfile>()
                .HasMany(u => u.UserBookmarks)
                .WithRequired(ub => ub.User)
                .HasForeignKey(ub => ub.UserId)
                .WillCascadeOnDelete(false);

            mb.Entity<UserProfile>()
                .HasMany(u => u.UrlSettings)
                .WithRequired(s => s.User)
                .HasForeignKey(s => s.UserId)
                .WillCascadeOnDelete(false);

            mb.Entity<Url>()
                .HasMany(u => u.UserUrlSettings)
                .WithRequired(us => us.Url)
                .HasForeignKey(us => us.UrlId)
                .WillCascadeOnDelete(false);

        }
    }

    [System.ComponentModel.DataAnnotations.Schema.Table("UserProfile")]
    public class UserProfile //: IEntity
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Email { get; set; }
        public virtual ICollection<UserBookmark> UserBookmarks { get; set; }
        public virtual ICollection<UserUrlSettings> UrlSettings { get; set; }
        public virtual ICollection<UserReport> Reports { get; set; }
    }
    public class UserReport : IEntity
    {
        [Key]
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
        public Int64 Id { get; set; }
        public int UserId { get; set; }
        public string Message { get; set; }
        public string Title { get; set; }
        public string Contacts { get; set; }
        public virtual UserProfile User { get; set; }
    }
    public class Tag : IEntity
    {
        public Int64 Id { get; set; }
        public string TAG { get; set; }
        public int position { get; set; }
        public virtual ICollection<Bookmark> Bookmarks { get; set; }
    }
    public class Url : IEntity
    {
        public Int64 Id { get; set; }
        public string URI { get; set; }
        public string HostUrl { get; set; }
        public string Content { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string PrintScreenUri { get; set; }
        public string Favicon { get; set; }
        public DateTime LastModified { get; set; }
        public int position { get; set; }
        public bool isWWW { get; set; }
        public bool isFile { get; set; }
        public virtual ICollection<UserUrlSettings> UserUrlSettings { get; set; }
        public virtual ICollection<Bookmark> Bookmarks { get; set; }
    }
    public class Bookmark : IEntity
    {
        public Int64 Id { get; set; }
        public Int64 TagId { get; set; }
        public Int64 UrlId { get; set; }
        public bool isPrivate { get; set; }
        public int position { get; set; }

        public virtual ICollection<UserBookmark> UserBookmarks { get; set; }
        public virtual Tag Tag { get; set; }
        public virtual Url Url { get; set; }
    }
    public class UserBookmark : IEntity
    {
        public Int64 Id { get; set; }
        public Int64 BookmarkId { get; set; }
        public int UserId { get; set; }
        public int position { get; set; }
        public virtual Bookmark Bookmark { get; set; }
        public virtual UserProfile User { get; set; }
    }
    public class UserUrlSettings : IEntity
    {
        public Int64 Id { get; set; }
        public int UserId { get; set; }
        public Int64 UrlId { get; set; }
        public string Title { get; set; }
        public virtual UserProfile User { get; set; }
        public virtual Url Url { get; set; }
    }
}
